package com.sjb.cp.manager.auth;

/**
 * @Author:sjb
 * @CreateTime:2025-02-14
 * @Description: 用户在特定空间内的授权上下文，关联的图片、空间、用户信息
 * @Version：1.0
 */

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.json.JSONUtil;
import com.sjb.cp.exception.BusinessException;
import com.sjb.cp.exception.ErrorCode;
import com.sjb.cp.model.constant.SpaceUserPermissionConstant;
import com.sjb.cp.model.constant.UserConstant;
import com.sjb.cp.model.enums.SpaceRoleEnum;
import com.sjb.cp.model.enums.SpaceTypeEnum;
import com.sjb.cp.model.po.Picture;
import com.sjb.cp.model.po.Space;
import com.sjb.cp.model.po.SpaceUser;
import com.sjb.cp.model.po.User;
import com.sjb.cp.service.PictureService;
import com.sjb.cp.service.SpaceService;
import com.sjb.cp.service.SpaceUserService;
import com.sjb.cp.service.UserService;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@Data
public class SpaceUserAuthContext {

    @Value("${server.servlet.context-path}")
    private final String contextPath;

    @Resource
    private SpaceUserAuthManager spaceUserAuthManager;

    /**
     * 临时参数，不同请求对应的id不同
     */
    private Long id;

    private Long pictureId;

    private Long spaceId;

    private Long spaceUserId;

    private Picture picture;

    private Space space;

    private SpaceUser spaceUser;

    @Resource
    private SpaceUserService spaceUserService;

    @Resource
    private PictureService pictureService;

    @Resource
    private UserService userService;

    @Resource
    private SpaceService spaceService;

    /**
     * 从请求中获取上下文对象
     *
     * @return
     */
    private SpaceUserAuthContext getSpaceUserAuthContextByRequest() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getRequest();
        String contentType = request.getHeader(Header.CONTENT_TYPE.getValue());
        // 兼容get&post操作
        SpaceUserAuthContext spaceUserAuthContext = null;
        if (ContentType.JSON.getValue().equals(contentType)) {
            String body = ServletUtil.getBody(request);
            spaceUserAuthContext = JSONUtil.toBean(body, SpaceUserAuthContext.class);
        } else {
            Map<String, String> paramMap = ServletUtil.getParamMap(request);
            spaceUserAuthContext = BeanUtil.toBean(paramMap, SpaceUserAuthContext.class);
        }

        Long id = spaceUserAuthContext.getId();
        if (id != null) {
            String requestUri = request.getRequestURI();
            String partUri = requestUri.replace(contextPath + "/", "");
            String moduleName = StrUtil.subBefore(partUri, "/", false);

            switch (moduleName) {
                case "picture":
                    spaceUserAuthContext.setPictureId(id);
                    break;
                case "space":
                    spaceUserAuthContext.setSpaceId(id);
                    break;
                case "space_user":
                    spaceUserAuthContext.setSpaceUserId(id);
                    break;
                default:
            }
        }
        return spaceUserAuthContext;
    }

    /**
     * 获取权限列表
     *
     * @param loginId
     * @param loginType
     * @return
     */
    public List<String> getPermissionsList(Object loginId, String loginType) {
        // 校验登录类型：如果 loginType 不是 "space"，直接返回空权限列表。
        if (!StpKit.SPACE_TYPE.equals(loginType)) {
            return Collections.emptyList();
        }
        // 如果当前是管理员 返回管理员权限列表
        List<String> ADMIN_PERMISSIONS = spaceUserAuthManager.getPermissionList(SpaceRoleEnum.ADMIN.getValue());
        SpaceUserAuthContext spaceUserAuthContextByRequest = getSpaceUserAuthContextByRequest();
        // 如果所有字段都为空 默认公共空间
        if (isAllFiledIsNull(spaceUserAuthContextByRequest)) {
            return ADMIN_PERMISSIONS;
        }
        //  校验登录状态：通过 loginId 获取当前登录用户信息。如果用户未登录，抛出未授权异常；否则获取用户的唯一标识 userId，用于后续权限判断。
        User loginUser = (User) StpKit.SPACE.getSessionByLoginId(loginId).get(UserConstant.USER_LOGIN_STATE);
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "用户未登录");
        }
        Long userId = loginUser.getId();
        SpaceUser spaceUser = spaceUserAuthContextByRequest.getSpaceUser();
        if (spaceUser != null) {
            return spaceUserAuthManager.getPermissionList(spaceUser.getSpaceRole());
        }
        // 如果有spaceId 团队空间，从数据库中查询spaceUser对象
        Long spaceUserId = spaceUserAuthContextByRequest.getSpaceUserId();
        if (spaceUserId != null) {
            spaceUser = spaceUserService.getById(spaceUserId);
            if (spaceUser == null) {
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "未找到空间信息");
            }
            // 查询当前登录用户对象的spaceUser
            spaceUser = spaceUserService.lambdaQuery()
                    .eq(SpaceUser::getUserId, userId)
                    .eq(SpaceUser::getSpaceId, spaceId)
                    .one();
            if (!spaceUser.getUserId().equals(userId)) {
                // 当前登录用户不属于该空间 返回空的权限列表
                return Collections.emptyList();
            }
            String spaceRole = spaceUser.getSpaceRole();
            return spaceUserAuthManager.getPermissionList(spaceRole);
        }
        // 如果没有spaceUserId, 通过spaceId或者pictureId查询图片信息
        Long spaceId = spaceUserAuthContextByRequest.getSpaceId();
        if (spaceId == null) {
            // 如果没有spaceId，通过pictureId 获取picture和space对象
            Long pictureId = spaceUserAuthContextByRequest.getPictureId();
            if (pictureId == null) {
                return ADMIN_PERMISSIONS;
            }
            Picture picture = pictureService.lambdaQuery().select(Picture::getSpaceId, Picture::getUserId, Picture::getId)
                    .eq(Picture::getId, pictureId).one();
            if (picture == null) {
                // 没有对象的图片信息
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "请求图片信息不存在");
            }
            spaceId = picture.getSpaceId();
            // 公共图库 仅管理员和本人可操作
            if (spaceId == null) {
                if (picture.getUserId().equals(userId) || userService.isAdmin(loginUser)) {
                    return ADMIN_PERMISSIONS;
                } else {
                    // 仅可查看功能
                    return Collections.singletonList(SpaceUserPermissionConstant.PICTURE_VIEW);
                }
            }
        }
        // 获取space对象
        Space space = spaceService.getById(spaceId);
        if (space == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "未找到空间信息");
        }
        // 根据空间类型判断权限
        if (space.getSpaceType() == SpaceTypeEnum.PRIVATE.getValue()) {
            // 私有空间 仅本人或管理员编辑
            if (space.getUserId().equals(userId) || userService.isAdmin(loginUser)) {
                return ADMIN_PERMISSIONS;
            } else {
                return Collections.emptyList();
            }
        } else {
            // 团队空间 查询角色和权限
            spaceUser = spaceUserService.lambdaQuery().eq(SpaceUser::getSpaceId, spaceId)
                    .eq(SpaceUser::getUserId, userId)
                    .one();
            if (spaceUser == null) {
                return Collections.emptyList();
            }
            String spaceRole = spaceUser.getSpaceRole();
            return spaceUserAuthManager.getPermissionList(spaceRole);
        }
    }


    /**
     * 判断所有字段是否为空
     *
     * @param object
     * @return
     */
    private boolean isAllFiledIsNull(Object object) {
        // 对象本身为空
        if (object == null) {
            return true;
        }
        // 对比字段是否为空
        return Arrays.stream(ReflectUtil.getFields(object.getClass()))
                .map(result -> ReflectUtil.getFieldValue(object, result))
                .allMatch(ObjectUtil::isNull);
    }
}